---
title: 'Credential Management'
description: 'Extend Droidrun with secure credential management'
---

## Overview

Secure storage for passwords, API keys, and tokens.
- Stored in YAML files or in-memory dicts
- Never logged or exposed
- Auto-injected as `type_secret` action
- Simple string or dict format

## Quick Start

### Method 1: In-Memory (Recommended for SDK)

```python
import asyncio
from droidrun import DroidAgent, DroidrunConfig

async def main():
    # Define credentials directly
    credentials = {
        "MY_PASSWORD": "secret123",
        "API_KEY": "sk-1234567890"
    }

    config = DroidrunConfig()

    agent = DroidAgent(
        goal="Login to my app",
        config=config,
        credentials=credentials  # Pass directly
    )

    result = await agent.run()
    print(result.success)

asyncio.run(main())
```

### Method 2: YAML File

1. **Create credentials file:**

```yaml
# credentials.yaml
secrets:
  # Dict format (recommended)
  MY_PASSWORD:
    value: "your_password_here"
    enabled: true

  GMAIL_PASSWORD:
    value: "gmail_pass_123"
    enabled: true

  # Simple string format (auto-enabled)
  API_KEY: "sk-1234567890abcdef"

  # Disabled secret
  OLD_PASSWORD:
    value: "old_pass"
    enabled: false  # Not loaded
```

2. **Enable in config.yaml:**

```yaml
# config.yaml
credentials:
  enabled: true
  file_path: credentials.yaml
```

3. **Use in code:**

```python
from droidrun import DroidAgent, DroidrunConfig

# Config loads credentials from file
config = DroidrunConfig.from_yaml("config.yaml")

agent = DroidAgent(
    goal="Login to Gmail",
    config=config  # Credentials loaded automatically
)
```

---

## How Agents Use Credentials

When credentials are provided, the `type_secret` action is **automatically available**:

### Executor/Manager Mode
```json
{
  "action": "type_secret",
  "secret_id": "MY_PASSWORD",
  "index": 5
}
```

### CodeAct Mode
```python
type_secret("MY_PASSWORD", index=5)
```

The agent never sees the actual value - only the secret ID.

---

## Example: Login Automation

```python
import asyncio
from droidrun import DroidAgent, DroidrunConfig

async def main():
    credentials = {
        "EMAIL_USER": "user@example.com",
        "EMAIL_PASS": "secret_password"
    }

    config = DroidrunConfig()

    agent = DroidAgent(
        goal="Open Gmail and login with my credentials",
        config=config,
        credentials=credentials
    )

    result = await agent.run()
    print(f"Success: {result.success}")

asyncio.run(main())
```

**What the agent does:**
1. Opens Gmail: `open_app("Gmail")`
2. Clicks email field: `click(index=3)`
3. Types email: `type("user@example.com", index=3)`
4. Clicks password field: `click(index=5)`
5. Types password securely: `type_secret("EMAIL_PASS", index=5)`
6. Clicks login: `click(index=7)`

## Credentials vs Variables

| Feature | Credentials | Variables |
|---------|------------|-----------|
| **Purpose** | Passwords, API keys | Non-sensitive data |
| **Storage** | YAML or in-memory | In-memory only |
| **Logging** | Never logged | May appear in logs |
| **Access** | Via `type_secret` tool | In shared state |
| **Security** | Protected | No protection |

**Example: Using Variables**
```python
variables = {
    "target_email": "john@example.com",
    "subject_line": "Monthly Report"
}

agent = DroidAgent(
    goal="Compose email to {{target_email}}",
    config=config,
    variables=variables  # Non-sensitive
)
```

---

## Troubleshooting

### Error: Credential manager not initialized

**Solution:**
```yaml
# config.yaml
credentials:
  enabled: true  # Must be true
  file_path: credentials.yaml
```

Or:
```python
agent = DroidAgent(..., credentials={"PASSWORD": "secret"})
```

### Error: Secret 'X' not found

**Check available secrets:**
```python
from droidrun.credential_manager import FileCredentialManager

cm = FileCredentialManager("credentials.yaml")
print(await cm.get_keys())
```

**Verify in YAML:**
```yaml
secrets:
  X:
    value: "your_value"
    enabled: true  # Must be true
```

---

## Custom Credential Managers

Extend `CredentialManager` for custom secret storage:

```python
from droidrun.credential_manager import CredentialManager

class MyCredentialManager(CredentialManager):
    def __init__(self, api_key):
        self.api_key = api_key

    async def resolve_key(self, key: str) -> str:
        # Implement your own credential retrieval logic
        return await fetch_from_service(key, self.api_key)

    async def get_keys(self) -> list[str]:
        # Return list of available credential keys
        return await fetch_available_keys(self.api_key)

# Use it
credentials = MyCredentialManager(api_key="...")
agent = DroidAgent(goal="Login", config=config, credentials=credentials)
```

Implement any custom secret storage backend.

---

## Related

See [Configuration Guide](/sdk/configuration) for credential setup.

See [Custom Variables](/features/custom-variables) for non-sensitive data.
